package com.centerm.bluetooth.lklcommon.controller;

import android.content.Context;
import android.support.annotation.NonNull;
import android.text.TextUtils;

import com.centerm.bluetooth.core.controller.BaseController;
import com.centerm.bluetooth.core.controller.constants.WaitEnum;
import com.centerm.bluetooth.ibridge.BluetoothIBridgeDevice;
import com.centerm.bluetooth.lklcommon.Command;
import com.centerm.bluetooth.lklcommon.listener.ITrackListener;
import com.centerm.bluetooth.lklcommon.mode.Track;
import com.centerm.bluetooth.model.Respond;
import com.centerm.bluetooth.model.RespondStatus;
import com.centerm.util.HexUtil;
import com.centerm.util.Logger;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * Created by linwenhui on 2017/5/12.
 */

public class TrackController extends BaseController<ITrackListener> {

    public TrackController(@NonNull Context context) {
        super(context);
    }

    /**
     * 开启读卡器
     *
     * @param mode        读卡模式
     * @param timeout     超时时间
     * @param displayMode 交易显示信息模式
     * @param tradeType   交易类型
     * @param money       交易金额
     * @param desInfo     全屏信息(可选)
     * @return
     */
    public boolean openTrackCardRead(int mode, int timeout, int displayMode, String tradeType, String money, String desInfo) throws IOException {

        if (wait != WaitEnum.FREE)
            return false;

        ByteArrayOutputStream params = new ByteArrayOutputStream();
        // 读卡模式
        params.write(mode);
        // 超时时间
        params.write(timeout);
        // 交易显示信息模式
        params.write(displayMode);
        // 交易类型
        if (TextUtils.isEmpty(tradeType)) {
            params.write(new byte[]{0x00, 0x00});
        } else {
            byte[] tradeTypeBytes = tradeType.getBytes("GBK");
            byte[] tradeTypeLenBytes = HexUtil.toLen(tradeType.length() * 2);
            params.write(tradeTypeLenBytes);
            params.write(tradeTypeBytes);
        }
        // 交易金额
        int moneyLen = money.length();
        if (moneyLen > 12) {
            moneyLen = 12;
            money = money.substring(0, 12);
        }
        params.write(HexUtil.toLen(moneyLen));
        params.write(money.getBytes("UTF-8"));

        // 全屏信息(可选)
        if (TextUtils.isEmpty(desInfo)) {
            params.write(new byte[]{0, 0});
        } else {
            byte[] desInfoBytes = desInfo.getBytes("GBK");
            byte[] desInfoLenBytes = HexUtil.toLen(desInfoBytes.length);
            params.write(desInfoLenBytes);
            params.write(desInfoBytes);
        }
        boolean res = send(Command.TRACK_OPEN_CARD, params.toByteArray());
        if (res)
            setTimeOut(timeout);
        params.close();
        return res;
    }

    protected void parseOpenTrackCardRead(byte[] content) {
        if (baseListener != null)
            baseListener.onCardType(content[0]);
    }

    /**
     * 读磁条卡信息
     *
     * @param mode 磁道信息读取模式
     * @param mask 主帐号屏蔽掩码(10个字节) 0与F分别表示需要显示或屏蔽的 例如 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00表示前8个主帐号显示，后6个主帐号显示，中间部分屏蔽，用E代替
     * @return
     */
    public boolean readTrackData(int mode, @NonNull byte[] mask) throws IOException {

        if (wait != WaitEnum.FREE)
            return false;

        ByteArrayOutputStream params = new ByteArrayOutputStream();
        //磁道信息读取模式
        params.write(mode);
        //主帐号屏蔽掩码
        params.write(mask);
        boolean res = send(Command.READ_TRACK_DATA, params.toByteArray());
        if (res)
            setTimeOut(DEFAULT_TIMEOUT);
        params.close();
        return res;
    }

    protected void parseTrackData(byte[] data) {
        //刷卡响应状态
        byte status = data[0];
        if (status == 0) {
            //磁道信息指示位
            byte mode = data[1];
            Track track = new Track();
            // KSN号
            byte[] ksnBytes = new byte[8];
            System.arraycopy(data, 2, ksnBytes, 0, 8);
            track.setKsn(HexUtil.byte2HexStr(ksnBytes));

            // 随机数
            byte[] randomBytes = new byte[8];
            System.arraycopy(data, 10, randomBytes, 0, 8);
            track.setRandom(HexUtil.byte2HexStr(randomBytes));

            //主账号
            byte[] panBytes = new byte[10];
            System.arraycopy(data, 18, panBytes, 0, 10);
            track.setPan(HexUtil.byte2HexStr(panBytes));

            //YYMM
            byte[] expireDT = new byte[2];
            System.arraycopy(data, 28, expireDT, 0, 2);
            track.setExpire(HexUtil.byte2HexStr(expireDT));

            //一磁长度
            byte track1Len = data[30];

            if ((track1Len & 0xFF) == 0xFF)
                track1Len = 0;
            //二磁长度
            byte track2Len = data[31];
            if ((track2Len & 0xFF) == 0xFF)
                track2Len = 0;


            //三磁长度
            byte track3Len = data[32];
            if ((track3Len & 0xFF) == 0xFF)
                track3Len = 0;

            //二三磁道加密数据
            byte[] twoThreeLenByte = new byte[2];
            System.arraycopy(data, 33, twoThreeLenByte, 0, 2);
            int twoThreeLen = 0;
            try {
                twoThreeLen = Integer.valueOf(HexUtil.byte2HexStr(twoThreeLenByte));
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
            if (twoThreeLen > 0) {
                byte[] twoThreeBytes = new byte[twoThreeLen];
                System.arraycopy(data, 35, twoThreeBytes, 0, twoThreeLen);
                track.setTrack2(HexUtil.byte2HexStr(twoThreeBytes));
            }

            //一磁道加密数据
            byte[] OneLenByte = new byte[2];
            System.arraycopy(data, 35 + twoThreeLen, OneLenByte, 0, 2);
            try {
                track1Len = Byte.valueOf(HexUtil.byte2HexStr(OneLenByte));
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }

            if (track1Len > 0) {
                byte[] track1Data = new byte[track1Len];
                System.arraycopy(data, 37 + twoThreeLen, track1Data, 0, track1Len);
                track.setTrack1(HexUtil.byte2HexStr(track1Data));
            }
            // 二磁的有效期和服务 代码
            byte[] serviceCode = new byte[7];
            System.arraycopy(data, 37 + twoThreeLen, serviceCode, 0, 7);
            track.setCode(HexUtil.toASCII(serviceCode));
            if (baseListener != null)
                baseListener.onSwiperSuc(track);
        } else {
            if (baseListener != null)
                baseListener.onSwiperError();
        }
    }

    /**
     * 开启读卡器 -增强安全指令
     *
     * @param mode        读卡模式
     * @param timeout     超时时间
     * @param displayMode 交易显示信息模式
     * @param tradeType   交易类型
     * @param money       交易金额
     * @param desInfo     全屏信息(可选)
     * @param serviceCode 业务代码
     * @param featureCode 服务端特征码
     * @param extralInfo  附加信息
     * @return
     */
    public boolean openTrackCardReadSafe(int mode, int timeout, int displayMode, String tradeType, String money, String desInfo, String serviceCode, String featureCode, String extralInfo) throws IOException {

        if (wait != WaitEnum.FREE)
            return false;

        ByteArrayOutputStream params = new ByteArrayOutputStream();
        // 读卡模式
        params.write(mode);
        // 超时时间
        params.write(timeout);
        // 交易显示信息模式
        params.write(displayMode);
        // 交易类型
        if (TextUtils.isEmpty(tradeType)) {
            params.write(new byte[]{0x00, 0x00});
        } else {
            byte[] tradeTypeBytes = tradeType.getBytes("GBK");
            // 长度
            params.write(HexUtil.toLen(tradeTypeBytes.length));
            params.write(tradeTypeBytes);
        }
        // 交易金额
        int moneyLen = money.length();
        params.write(HexUtil.toLen(moneyLen));
        params.write(money.getBytes("GBK"));

        // 全屏信息(可选)
        if (TextUtils.isEmpty(desInfo)) {
            params.write(new byte[]{0x00, 0x00});
        } else {
            byte[] desInfoBytes = desInfo.getBytes("GBK");
            params.write(HexUtil.toLen(desInfoBytes.length));
            params.write(desInfoBytes);
        }

        // 业务代码
        if (TextUtils.isEmpty(serviceCode)) {
            params.write(new byte[]{0x00, 0x00});
        } else {
            byte[] serviceCodeBytes = serviceCode.getBytes("GBK");
            params.write(HexUtil.toLen(serviceCodeBytes.length));
            params.write(serviceCodeBytes);
        }

        // 服务端特征码
        if (TextUtils.isEmpty(featureCode)) {
            params.write(new byte[]{0x00, 0x00});
        } else {
            byte[] featureCodeBytes = featureCode.getBytes("GBK");
            params.write(HexUtil.toLen(featureCodeBytes.length));
            params.write(featureCodeBytes);
        }

        // 附加信息
        if (TextUtils.isEmpty(extralInfo)) {
            params.write(new byte[]{0x00, 0x00});
        } else {
            byte[] extralInfoBytes = extralInfo.getBytes("GBK");
            params.write(HexUtil.toLen(extralInfoBytes.length));
            params.write(extralInfoBytes);
        }

        boolean res = send(Command.TRACK_OPEN_CARD_SAFE, params.toByteArray());
        if (res)
            setTimeOut(timeout);
        params.close();
        return res;
    }

    protected void parseTrackCardReadSafe(byte[] content) {
        if (baseListener != null)
            baseListener.onCardTypeSafe(content[0]);
    }

    /**
     * 读磁条卡 -增强安全指令
     *
     * @param mode 磁道信息读取模式
     * @param mask 主帐号屏蔽掩码(10个字节) 0与F分别表示需要显示或屏蔽的 例如 0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00表示前8个主帐号显示，后6个主帐号显示，中间部分屏蔽，用E代替
     * @return
     * @throws IOException
     */
    public boolean readTrackDataSafe(int mode, @NonNull byte[] mask) throws IOException {

        if (wait != WaitEnum.FREE)
            return false;

        ByteArrayOutputStream params = new ByteArrayOutputStream();
        // 磁道信息读取模式
        params.write(mode);
        // 主帐号屏蔽掩码
        params.write(mask);
        boolean res = send(Command.READ_TRACK_DATA_SAFE, params.toByteArray());
        if (res)
            setTimeOut(DEFAULT_TIMEOUT);
        params.close();
        return res;
    }

    @Override
    public void onDataReceived(BluetoothIBridgeDevice device, Respond respond) {
        super.onDataReceived(device, respond);
        switch (HexUtil.byte2HexStr(respond.getCmd()).toUpperCase()) {
            // 开启读卡器
            case Command.TRACK_OPEN_CARD_STRING:
                parseOpenTrackCardRead(respond.getContent());
                break;
            // 读磁条卡信息
            case Command.READ_TRACK_DATA_STRING:
            case Command.READ_TRACK_DATA_SAFE_STRING:
                parseTrackData(respond.getContent());
                break;
            // 开启读卡器 -增强安全指令
            case Command.TRACK_OPEN_CARD_SAFE_STRING:
                parseTrackCardReadSafe(respond.getContent());
                break;
        }

    }

    @Override
    public void onDataReceivedError(BluetoothIBridgeDevice device, Respond respond) {
        cancelTimer();
        Logger.i(" cmd == " + HexUtil.byte2HexStr(respond.getCmd()) + " == " + respond.getRespondStatus() + " wait == " + wait);
        final String cmdString = HexUtil.byte2HexStr(respond.getCmd());
        if (baseListener != null) {
            if (Command.TRACK_OPEN_CARD_SAFE_STRING.equals(cmdString) || Command.TRACK_OPEN_CARD_STRING.equals(cmdString)) {
                if (respond.getRespondStatus() == RespondStatus.ERROR_OTHER) {
                    baseListener.onSwiperCancel();
                } else if (respond.getRespondStatus() == RespondStatus.TIMEOUT) {
                    baseListener.onSwiperTimeout();
                }
            } else {
                super.onDataReceivedError(device, respond);
            }
        }
    }
}
